require("common")
package.cpath = string.format("%s;%s", package.cpath, common.getConfig("path.cpath"))
require("gui")
require("form")
require("plugin")
require("layout")

stoicheia = {
	new = function()
		local self = {}
		setmetatable(self, { __index = stoicheia })
		self.plugin = plugin.new(self)
		self.plugin:loadAll()
		self.screen = {}
		self.controlHeight = 90
		self.controlGap = 0
		self.controlShiftWidth = 33
		self.controlLeftGap = 10
		self.controlRightGap = 10
		self.controlInGap = 10
		
		log("stoicheia", "Selected language is: %s", common.getLanguage())
		self:check()
		
		self.gui = gui.new(2)
		self.gui.pagewin = self.gui.windows[1]
		self.gui.controlwin = self.gui.windows[2]
		
		self.gui.controlwin:visible(true)
		self.gui.controlwin:size(1, self.controlHeight)
		self.gui.controlwin:zindex("front")
		self.gui.controlwin:scroll(false)
		
		self.gui.handler:add("SCREEN", function(gui, id, arg)
			local values = arg:split(" ")
			assert(#values == 2, "Unknown screen argument: " .. arg)
			self.screen.width = tonumber(values[1])
			self.screen.height = tonumber(values[2])
			log("stoicheia", "Screen size is %dx%d", self.screen.width, self.screen.height)
			self:showStartPage()
		end)
		
		self.gui.handler:add("TIMER", function(gui, id)
			self:timerEvent()
		end)
		
		self.gui.controlwin.handler:add("STATUS", function(window, id, arg)
			if arg == "" then return end
			local prefix = "CLICKED "
			if arg:startsWith(prefix) then
				self:controlEvent(arg:sub(#prefix + 1))
			else
				log("stoicheia", "Unknown control status `%s'", arg)
			end
		end)
		
		self.gui.pagewin.handler:add("STATUS", function(window, id, arg)
			if arg == "" then return end
			local dummy, count = arg:gsub("(.-) (.*)", function(key, value)
				self:pageEvent(key, value)
			end)
			if count == 0 then
				log("stoicheia", "Unknown page status `%s'", arg)
			end
		end)
		
		self.gui.controlwin.handler:add("FINISHED", function(window, id)
			self:showControls(true)
		end)
		
		self.gui.pagewin.handler:add("FINISHED", function(window, id, arg)
			self:pageReady(arg)
		end)
		
		return self
	end,
	
	timerEvent = function(self)
		for i, p in pairs(self.plugin.items) do
			if p.timerEvent then p:timerEvent() end
		end
	end,
	
	pageEvent = function(self, event, arg)
		if self.plugin.current then
			self.plugin.current:pageEvent(event, arg)
		else
			assert(event == "CLICKED", "Unknown event on start screen: " .. event)
			self.plugin:activate(arg, self)
		end
	end,
	
	pageReady = function(self, url)
		if self.plugin.current then
			if self.plugin.current.pageReady then
				self.plugin.current:pageReady(url)
			end
		end
	end,
	
	controlEvent = function(self, event)
		if event == "CONTROL-SHIFT" then
			self.controlMinimized = not self.controlMinimized
			self:showControls(true, self.controlMinimized)
			return
		end
		if self.plugin.current then
			self:hiliteControl(event, true)
			self.plugin.current:controlEvent(event)
			self:hiliteControl(event, false)
		else
			if event == "finish" then self:exit() end
		end
	end,
	
	getScreenSize = function(self)
		return self.screen.width, self.screen.height
	end,
	
	open = function(self, path)
		self.gui.pagewin:open("file://" .. common.absolutePath(path))
	end,
	
	showPage = function(self, name, handler)
		local f = form.new(name)
		local screenWidth, screenHeight = self:getScreenSize()
		f:beginForm(screenWidth, screenHeight, common.getConfig("screen.background"), handler, false)
		f:beginFormHtml()
		if handler then handler("html", f) end
		f:endFormHtml()
		f:beginFormSvg()
		local clockRadius = common.getConfig("screen.clock.radius")
		local clockGap = common.getConfig("screen.clock.gap")
		local gap = 10
		f:renderFormClock(
			clockRadius,
			screenWidth - clockRadius - clockGap,
			clockRadius + clockGap
		)
		if handler then handler("svg", f) end
		f:endFormSvg()
		f:endForm()
		f:close()
		self.gui.pagewin:scroll(false)
		self:open(f.path)
		self.gui.pagewin:visible(true)
	end,
	
	showStartPage = function(self)
		log("stoicheia", "Showing start page")
		self.plugin:deactivate()
		local screenWidth, screenHeight = self:getScreenSize()
		local hw = screenWidth / 2
		local hh = screenHeight / 2
		self:showPage("start", function(event, f)
			if event == "html" then
				local labelMaxWidth = 300
				self.plugin:traverse(function(name, item, conf)
					local x = conf.icon.x * hw + hw
					local y = conf.icon.y * hh + hh
					f:renderFormLabel(common.getResource("plugin." .. name), name, x - (labelMaxWidth / 2), y + 50, labelMaxWidth)
				end)
				return
			end
			if event == "svg" then
				self.plugin:traverse(function(name, item, conf)
					local x = conf.icon.x * hw + hw
					local y = conf.icon.y * hh + hh
					f:renderFormSvg(name, x, y, 1, name)
				end)
				return
			end
		end)
		self:setControls(true, "finish")
	end,
	
	renderControlsForm = function(self, f, height, controls, pageview, minimize)
		local totalWidth = self.controlLeftGap
		local controlItems = common.getConfig("controls.items")
		for i, name in pairs(controls) do
			totalWidth = totalWidth + f:getControlWidth(name)
			if i > 1 then totalWidth = totalWidth + self.controlInGap end
		end
		if minimize ~= nil then
			if #controls > 0 then totalWidth = totalWidth + self.controlInGap end
			totalWidth = totalWidth + self.controlShiftWidth
		end
		totalWidth = totalWidth + self.controlRightGap
		
		local background = common.getConfig("screen.background")
		local buttonPrefix
		if pageview then buttonPrefix = "button_pageview" else buttonPrefix = "button_console" end
		f:beginForm(totalWidth, height, background, function(event, f)
			if event == "style" then
				local topGap = 5
				if pageview then topGap = 11 end
				local css = {
					[".controls"] = {},
					[".controls-l"] = {},
					[".controls-r"] = {},
					[".controls-m"] = {},
					[".controls-inner"] = { height = "90px" },
					[".control"] = { position = "absolute", top = topGap .. "px" },
					[".control-l"] = { background = string.format("url(%s) left center no-repeat", f:getImageUrl(string.format("%s_static_l.png", buttonPrefix))) },
					[".control-r"] = { background = string.format("url(%s) right center no-repeat", f:getImageUrl(string.format("%s_static_r.png", buttonPrefix))) },
					[".control-m"] = { background = string.format("url(%s) center center repeat-x", f:getImageUrl(string.format("%s_static_m.png", buttonPrefix))), margin = "0px 39px" },
					[".control-hilite .control-l"] = { ["background-image"] = string.format("url(%s)", f:getImageUrl(string.format("%s_hilite_l.png", buttonPrefix))) },
					[".control-hilite .control-r"] = { ["background-image"] = string.format("url(%s)", f:getImageUrl(string.format("%s_hilite_r.png", buttonPrefix))) },
					[".control-hilite .control-m"] = { ["background-image"] = string.format("url(%s)", f:getImageUrl(string.format("%s_hilite_m.png", buttonPrefix))) },
					[".control-inner"] = { height = "79px", color = "#ffffff", ["font-size"] = "42px", ["font-family"] = "\"Century Schoolbook L\" \"Nimbus Roman No9 L\" serif" },
					[".control-inner-2"] = { position = "relative", top = "7px", overflow = "hidden", ["text-align"] = "center", cursor = "default" },
					[".control-minimize, .control-maximize"] = { height = "79px", width = self.controlShiftWidth .. "px", position = "absolute", top = topGap .. "px" },
					[".control-minimize"] = { ["background"] = string.format("url(%s) center center no-repeat", f:getImageUrl("console_minimize.png")) },
					[".control-maximize"] = { ["background"] = string.format("url(%s) center center no-repeat", f:getImageUrl("console_maximize.png")) },
				}
				if pageview then
					css[".controls"] = { background = string.format("url(%s) left top no-repeat", f:getImageUrl(background)) }
				else
					css[".controls-l"] = { background = string.format("url(%s) left center no-repeat", f:getImageUrl("console_background_l.png")) }
					css[".controls-r"] = { background = string.format("url(%s) right center no-repeat", f:getImageUrl("console_background_r.png")) }
					css[".controls-m"] = { background = string.format("url(%s) center center repeat-x", f:getImageUrl("console_background_m.png")) }
				end
				f.r:cssSheet(css)
				return
			end
			if event == "script" then
				f:renderImagePreload(1, string.format("%s_hilite_l.png", buttonPrefix))
				f:renderImagePreload(2, string.format("%s_hilite_r.png", buttonPrefix))
				f:renderImagePreload(3, string.format("%s_hilite_m.png", buttonPrefix))
				return
			end
		end)
		f:beginFormHtml()
		f:beginControls(totalWidth)
		local left = self.controlLeftGap
		for i, name in pairs(controls) do
			local width = f:getControlWidth(name)
			if i > 1 then left = left + self.controlInGap end
			f:renderControl(name, width, left)
			left = left + width
		end
		if minimize ~= nil then
			if #controls > 0 then left = left + self.controlInGap end
			f:renderControlShift(minimize, left)
		end
		f:endControls()
		f:endFormHtml()
		f:endForm()
		
		return totalWidth
	end,
	
	setControls = function(self, pageview, ...)
		if table.equals(self.currentControls, { ... }) then return end
		self:showControls(false)
		local form = form.new("controls")
		local minimize
		if not pageview then minimize = true end
		self.controlWidth = self:renderControlsForm(form, self.controlHeight, { ... }, pageview, minimize)
		form:close()
		self.gui.controlwin:size(self.controlWidth, self.controlHeight)
		self.gui.controlwin:open("file://" .. common.absolutePath(form.path))
		self.currentControls = { ... }
		self.controlMinimized = false
	end,
	
	showControls = function(self, on, minimize)
		local y = self.controlGap
		local x = self.controlGap
		if not on then y = -self.controlHeight end
		if minimize ~= nil then
			self.controlMinimized = minimize
			local css
			if minimize then css = "maximize" else css = "minimize" end
			self.gui.controlwin:exec(string.format("setClass('control_shift', 'control-%s');", css))
		end
		if self.controlMinimized then
			x = self.controlShiftWidth + self.controlInGap + self.controlRightGap - self.controlWidth
		end
		self.gui.controlwin:position(x, y)
	end,
	
	showPagewin = function(self, on)
		-- self.gui.pagewin:visible(on)
		local w, h = self:getScreenSize()
		local y
		if on then y = 0 else y = h end
		self.gui.pagewin:position(0, y)
	end,
	
	hiliteControl = function(self, name, on)
		if self.plugin.current then
			if self.plugin.current.hiliteControl then
				if not self.plugin.current:hiliteControl(name, on) then
					return
				end
			end
		end
		self:hiliteControlRaw(name, on)
	end,
	
	hiliteControlRaw = function(self, name, on)
		local css = ""
		if on then css = "control-hilite" end
		self.gui.controlwin:exec(string.format("setClass('control_%s', 'control %s');", name, css))
	end,
	
	checkCmd = function(self, expected, command, ...)
		log("stoicheia", "Checking external command `%s'", command)
		local missing = 32512
		local err = task.execute(command, ...)
		if err == expected then
			log("stoicheia", "Command `%s' runned as expected", command)
			return
		end
		log("stoicheia", "Command `%s' exited with wrong error code: %d", command, err)
		print()
		print()
		print("======================================================================")
		print(">>                             Error                                <<")
		print("======================================================================")
		print(string.format("Command `%s' doesn't work as expected:", command))
		print("Calling: " .. command, ...)
		print(string.format("Return code was %d, expected %d", err, expected))
		print(string.format("Please install correct version of program `%s' and/or put it into correct PATHs", command))
		if err == missing then
			print(string.format("Hint: error code %d means command is not installed", err))
		end
		print("======================================================================")
		os.exit(1)
	end,
	
	checkEnv = function(self, name)
		local value = os.getenv(name)
		if value ~= nil then return end
		print()
		print()
		print("======================================================================")
		print(">>                             Error                                <<")
		print("======================================================================")
		print(string.format("Environment variable `%s' is not set, please set and export this variable", name))
		print("======================================================================")
		os.exit(1)
	end,
	
	check = function(self)
		self:checkEnv("HOME")
		self:checkEnv("USER")
		self:checkCmd(0, "find", ".", "-maxdepth", 0)
		self:checkCmd(0, "pwd")
		self:checkCmd(0, "sleep", "--version")
		self:checkCmd(0, "mount", "-V")
		self:checkCmd(0, "umount", "-V")
		self:checkCmd(0, "mkdir", "--version")
		self:checkCmd(0, "mkfifo", "--version")
		self:checkCmd(0, "pgrep", ".")
		self:checkCmd(0, "aplay", "--version")
		self:checkCmd(256, "xsetroot", "-help")
		self.plugin:check()
	end,
	
	mountMedia = function(self, on)
		local paths = common.getConfig("path.media")
		local err = util.mount(paths, on)
		local action
		if on then action = "Mounted" else action = "Unmounted" end
		log("stoicheia", "%s %d branches with %d errors", action, #paths, err)
	end,
	
	clear = function(self, color)
		if color == nil then color = common.getConfig("screen.clearColor") end
		task.execute("xsetroot", "-solid", color)
	end,
	
	loop = function(self)
		self.gui:timer(1000)
		self.gui:loop()
		self.plugin:destroy()
	end,
	
	exit = function(self)
		self.gui:exit()
	end
}


